What is @asyncapi/parser?
@asyncapi/parser is a powerful npm package designed to parse AsyncAPI documents. It allows developers to read, validate, and manipulate AsyncAPI specifications programmatically. This is particularly useful for generating documentation, creating mock servers, and integrating with other tools in the API development lifecycle.
What are @asyncapi/parser's main functionalities?
Parsing AsyncAPI Documents
This feature allows you to parse an AsyncAPI document from a JSON string. The parsed document can then be used for further processing or validation.
const { Parser } = require('@asyncapi/parser');
const parser = new Parser();
const asyncapiDocument = `{
"asyncapi": "2.0.0",
"info": {
"title": "Streetlights API",
"version": "1.0.0"
},
"channels": {
"light/measured": {
"description": "Channel for light measurement events",
"subscribe": {
"summary": "Receive light measurement events",
"message": {
"$ref": "#/components/messages/LightMeasured"
}
}
}
},
"components": {
"messages": {
"LightMeasured": {
"payload": {
"type": "object",
"properties": {
"lumens": {
"type": "integer"
}
}
}
}
}
}
}`;
parser.parse(asyncapiDocument)
.then(doc => console.log('Parsed document:', doc))
.catch(err => console.error('Error parsing document:', err));
Validating AsyncAPI Documents
This feature allows you to validate an AsyncAPI document after parsing it. It checks for any schema violations or inconsistencies in the document.
const { Parser } = require('@asyncapi/parser');
const parser = new Parser();
const asyncapiDocument = `{
"asyncapi": "2.0.0",
"info": {
"title": "Streetlights API",
"version": "1.0.0"
},
"channels": {
"light/measured": {
"description": "Channel for light measurement events",
"subscribe": {
"summary": "Receive light measurement events",
"message": {
"$ref": "#/components/messages/LightMeasured"
}
}
}
},
"components": {
"messages": {
"LightMeasured": {
"payload": {
"type": "object",
"properties": {
"lumens": {
"type": "integer"
}
}
}
}
}
}
}`;
parser.parse(asyncapiDocument)
.then(doc => {
const validationErrors = doc.validate();
if (validationErrors.length) {
console.error('Validation errors:', validationErrors);
} else {
console.log('Document is valid');
}
})
.catch(err => console.error('Error parsing document:', err));
Accessing Document Components
This feature allows you to access various components of the parsed AsyncAPI document, such as channels and messages. This is useful for generating documentation or creating mock servers.
const { Parser } = require('@asyncapi/parser');
const parser = new Parser();
const asyncapiDocument = `{
"asyncapi": "2.0.0",
"info": {
"title": "Streetlights API",
"version": "1.0.0"
},
"channels": {
"light/measured": {
"description": "Channel for light measurement events",
"subscribe": {
"summary": "Receive light measurement events",
"message": {
"$ref": "#/components/messages/LightMeasured"
}
}
}
},
"components": {
"messages": {
"LightMeasured": {
"payload": {
"type": "object",
"properties": {
"lumens": {
"type": "integer"
}
}
}
}
}
}
}`;
parser.parse(asyncapiDocument)
.then(doc => {
const channels = doc.channels();
console.log('Channels:', channels);
const messages = doc.components().messages();
console.log('Messages:', messages);
})
.catch(err => console.error('Error parsing document:', err));
Other packages similar to @asyncapi/parser
swagger-parser
swagger-parser is a powerful npm package for parsing, validating, and dereferencing Swagger (OpenAPI) documents. It offers similar functionalities to @asyncapi/parser but is focused on the OpenAPI specification. It is widely used for working with RESTful APIs.
openapi-schema-validator
openapi-schema-validator is a package designed to validate OpenAPI 3.0 schemas. While it does not offer parsing capabilities, it provides robust validation features similar to those found in @asyncapi/parser.
openapi-types
openapi-types is a TypeScript library that provides type definitions for OpenAPI specifications. It is useful for developers who want to ensure type safety when working with OpenAPI documents, similar to how @asyncapi/parser provides structure for AsyncAPI documents.
Use this package to parse and validate AsyncAPI documents —either YAML or JSON— in your Node.js or browser application. Updated bundle for the browser is always attached to the GitHub Release.
:warning: This package doesn't support AsyncAPI 1.x anymore. We recommend to upgrade to the latest AsyncAPI version using the AsyncAPI converter. If you need to convert documents on the fly, you may use the Node.js or Go converters.
Install
npm install @asyncapi/parser
The parser by default supports AsyncAPI Schema Format and JSON Schema Format. For additional formats, you need to install additional plugins. For example:
- Avro schema
npm install @asyncapi/avro-schema-parser
- OpenAPI Schema Object
npm install @asyncapi/openapi-schema-parser
- RAML data type
npm install @asyncapi/raml-dt-schema-parser
Examples
Example passing inline AsyncAPI
const parser = require('@asyncapi/parser');
const doc = await parser.parse(`
asyncapi: '2.1.0'
info:
title: Example
version: '0.1.0'
channels:
example-channel:
subscribe:
message:
payload:
type: object
properties:
exampleField:
type: string
exampleNumber:
type: number
exampleDate:
type: string
format: date-time
`);
console.log(doc.info().title());
Example passing a URL
const parser = require('@asyncapi/parser');
const doc = await parser.parseFromUrl('https://my.server.com/example-asyncapi.yaml');
console.log(doc.info().title());
Example using Avro schemas
Head over to asyncapi/avro-schema-parser for more information.
Example using OpenAPI schemas
Head over to asyncapi/openapi-schema-parser for more information.
Example using RAML data types
Head over to asyncapi/raml-dt-schema-parser for more information.
API documentation
The parser API is generally structured the same way as the AsyncAPI specification, with additional support functions such as has<Something>()
. The parser uses wrapped functions to get the properties stored in JSON. This means in order to get the info object you would use the function doc.info()
and to get the title inside the info object you call doc.info().title()
.
See API documentation for more example and full API reference information.
Using in the browser
The package contains a built-in version of the parser, which is created via browserify
. To use it, you need to import the parser into the HTML file as below:
<script src="https://unpkg.com/@asyncapi/parser@latest/dist/bundle.js"></script>
<script>
const parser = window['AsyncAPIParser'];
...
</script>
Or, if you want to use a parser in a JS application of the SPA kind, import the parser as shown below:
import '@asyncapi/parser/dist/bundle';
const parser = window['AsyncAPIParser'];
...
Otherwise, if your application is bundled via bundlers like webpack
, you can import the parser like a regular package:
import parser from '@asyncapi/parser';
In case you just want to check out the latest bundle.js
without installing the package, we publish one on each GitHub release. You can find it under this link to the latest release.
Custom message parsers
AsyncAPI doesn't enforce one schema format for messages. You can have payload of your messages described with OpenAPI, Avro, etc. This parser by default parses only AsyncAPI schema format. You can extend it by creating a custom parser and registering it within the parser:
-
Create custom parser module that exports two functions:
module.exports = {
parse: ({ message, defaultSchemaFormat, originalAsyncAPIDocument, schemaFormat, fileFormat, parsedAsyncAPIDocument, pathToPayload }) => { },
getMimeTypes: () => [
'//mime types that will be used as the `schemaFormat` property of the message to specify its mime type',
'application/vnd.custom.type;version=1.0.0',
'application/vnd.custom.type+json;version=1.0.0',
]
}
-
Before parsing an AsyncAPI document with a parser, register the additional custom schema parser:
const myCustomParser = require('mycustomParser');
parser.registerSchemaParser(myCustomParser);
Error types
This package throws a bunch of different error types. All errors contain a type
(prefixed by this repo URL) and a title
field. The following table describes all the errors and the extra fields they include:
Type | Extra Fields | Description |
---|
null-or-falsey-document | None | The AsyncAPI document is null or a JS "falsey" value. |
invalid-document-type | None | The AsyncAPI document is not a string nor a JS object. |
invalid-json | detail , location | The AsyncAPI document is not valid JSON. |
invalid-yaml | detail , location | The AsyncAPI document is not valid YAML. |
impossible-to-convert-to-json | detail | Internally, this parser only handles JSON so it tries to immediately convert the YAML to JSON. This error means this process failed. |
missing-asyncapi-field | parsedJSON | The AsyncAPI document doesn't have the mandatory asyncapi field. |
unsupported-version | detail , parsedJSON , validationErrors | The version of the asyncapi field is not supported. Typically, this means that you're using a version below 2.0.0. |
dereference-error | parsedJSON , refs | This means the parser tried to resolve and dereference $ref's and the process failed. Typically, this means the $ref it's pointing to doesn't exist. |
unexpected-error | parsedJSON | We have our code covered with try/catch blocks and you should never see this error. If you see it, please open an issue to let us know. |
validation-errors | parsedJSON , validationErrors | The AsyncAPI document contains errors. See validationErrors for more information. |
impossible-to-register-parser | None | Registration of custom message parser failed. |
schema-validation-errors | parsedJSON , validationErrors | Schema of the payload provided in the AsyncAPI document is not valid with AsyncAPI schema format. |
fetch-url-error | None | The URL provided for fetching AsynAPI document is invalid. |
For more information about the ParserError
class, check out the documentation.
Custom extensions
The parser uses custom extensions to define additional information about the spec. Each has a different purpose but all of them are there to make it much easier to work with the AsyncAPI document. These extensions are prefixed with x-parser-
. The following extensions are used :
x-parser-spec-parsed
is used to specify if the AsyncAPI document is already parsed by the parser. Property x-parser-spec-parsed
is added to the root of the document with the true
value.x-parser-message-parsed
is used to specify if the message is already parsed by the message parser. Property x-parser-message-parsed
is added to the root of the document with the true
value.x-parser-message-name
is used to specify the name of the message if it is not provided. For messages without names, the parser generates anonymous names. Property x-parser-message-name
is added to a message object with a value that follows this pattern: <anonymous-message-${number}>
. This value is returned by message.uid()
when regular name
property is not present.x-parser-schema-id
is used to specify the ID of the schema if it is not provided. For schemas without IDs, the parser generates anonymous names. Property x-parser-schema-id
is added to every object of a schema with a value that follows this pattern: <anonymous-schema-${number}>
. This value is returned by schema.uid()
when regular $id
property is not present.x-parser-original-traits
is where traits are stored after they are applied on the AsyncAPI document. The reason is because the original traits
property is removed.x-parser-original-schema-format
holds information about the original schema format of the payload. You can use different schema formats with the AsyncAPI documents and the parser converts them to AsyncAPI schema. This is why different schema format is set, and the original one is preserved in the extension.x-parser-original-payload
holds the original payload of the message. You can use different formats for payloads with the AsyncAPI documents and the parser converts them to. For example, it converts payload described with Avro schema to AsyncAPI schema. The original payload is preserved in the extension.x-parser-circular
NOTE: All extensions added by the parser (including all properties) should be retrieved using special functions. Names of extensions and their location may change, and their eventual changes will not be announced.
Circular references
Parser dereferences all circular references by default. In addition, to simplify interactions with the parser, the following is added:
x-parser-circular
property is added to the root of the AsyncAPI document to indicate that the document contains circular references. Tooling developer that doesn't want to support circular references can use the hasCircular()
function to check the document and provide a proper message to the user.isCircular()
function is added to the Schema Model to determine if a given schema is circular with respect to previously occurring schemas in the tree.
Stringify
Converting a parsed document to a string may be necessary when saving the parsed document to a database, or similar situations where you need to parse the document just once and then reuse it.
For that, the Parser supports the ability to stringify a parsed AsyncAPI document through the static AsyncAPIDocument.stringify(...parsedDoc)
method. This method differs from the native JSON.stringify(...json)
implementation, in that every reference that occurs (at least twice throughout the document) is converted into a JSON Pointer path with a $ref:
prefix:
{
"foo": "$ref:$.some.path.to.the.bar"
}
To parse a stringified document into an AsyncAPIDocument instance, you must use the static AsyncAPIDocument.parse(...stringifiedDoc)
method. It isn't compatible with the native JSON.parse()
method. It replaces the given references pointed by the JSON Pointer path, with an $ref:
prefix to the original objects.
A few advantages of this solution:
- The string remains as small as possible due to the use of JSON Pointers.
- All circular references are preserved.
Develop
- Make sure you are using Node.js 14 or higher and npm 7 or higher
- Write code and tests.
- Make sure all tests pass
npm test
- Make sure code is well formatted and secure
npm run lint
Release regenerates API documentation and browser bundle, so you do not have to regenerate it manually with npm run docs
and npm run prepublishOnly
.
Contributing
Read CONTRIBUTING guide.
Contributors
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!